﻿//===============================================================================
// Microsoft Innovation Centre - Western Europe
// Copyright (c) 2008 Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious.  No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
//===============================================================================

using System;
using System.Collections.Generic;
using System.Data.Services;
using System.Linq;
using System.ServiceModel.Web;
using Microsoft.WVB.Server;

namespace Microsoft.WVB.Web
{
    [System.ServiceModel.ServiceBehavior(IncludeExceptionDetailInFaults = true)]   
    public class CDNDataService : DataService<Microsoft.WVB.Server.WVBDataModel>
    {
        public static void InitializeService(IDataServiceConfiguration config)
        {
            config.UseVerboseErrors = true;
            config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
            config.SetEntitySetAccessRule("*", EntitySetRights.All);

            //config.SetEntitySetAccessRule("Programs", EntitySetRights.AllRead);
            //config.SetEntitySetAccessRule("Schedules", EntitySetRights.AllRead);
            //config.SetEntitySetAccessRule("Channels", EntitySetRights.AllRead);
            //config.SetEntitySetAccessRule("Categories", EntitySetRights.AllRead);
            //config.SetEntitySetAccessRule("Broadcasters", EntitySetRights.AllRead);
        }
      
        /// <summary>
        /// Return the average rating for a given movie.
        /// </summary>
        /// <param name="pid">The Programid of the movie to be rated.</param>
        /// <param name="userId">The userid (identifier) of the user currently rating the movie.</param>
        /// <returns>The average rating for the given movie on a scale from 1 to 5</returns>
        [SingleResult]
        [WebGet]
        public IQueryable<Double> GetUserMovieRating(int pid, string userId)
        {
            Double rating = (from r in this.CurrentDataSource.Ratings
                    where r.programid == pid && r.UserIdentifier == userId
                    select r.Rate).FirstOrDefault();
            return new Double[] { rating }.AsQueryable<Double>();
        }

        /// <summary>
        /// This function set the rating for a given movie, from a given user
        /// if the operation completes successfully, the return value is the average rating
        /// for this given movie from users who have been rating it - including the "just" set rating 
        /// from th given user.
        /// </summary>
        /// <param name="pid">The Programid of the movie to be rated.</param>
        /// <param name="userId">The userid (identifier) of the user currently rating the movie.</param>
        /// <param name="rating">The rating the user gave to the given movie.</param>
        /// <returns>The average rating for the given movie, including the rating just set.</returns>
        [SingleResult]
        [WebGet]
        public IQueryable<Double> SetUserMovieRating(int pid, string userId, double rating)
        {
            ProgramProperty ratingProperty = null;
            ProgramProperty ratingNumberProperty = null;
            double newRating = 0.0; 
            int newNumber = 0;
            Double result = 0;
            
            int propMax = 0;
            IEnumerable<Program> query = null;
            Program program = null;

            if (CurrentDataSource.ProgramPropertyInfoCollection.Count() != 0)
            {
                propMax = (from pv in this.CurrentDataSource.ProgramPropertyInfoCollection
                    select pv.pvid).Max();            }

             if (CurrentDataSource.Programs.Count() != 0)
            {              
                query = from p in this.CurrentDataSource.Programs
                        where p.programid == pid
                        select p;
             }

             if ((query != null) && (query.Count() != 0))
             {
                 program = query.FirstOrDefault();                 
             }

            if (program != null)
            {
                program.Properties.Load();

                if (program.Properties.Count != 0)
                {
                    var pcol = program.Properties.FirstOrDefault((v) =>
                    {
                        if (v.PropertyInfo == null) 
                            v.PropertyInfoReference.Load(); 
                        return ((v.PropertyInfo.Name == "Rating") && (v.programid == pid));
                    });

                    if (pcol != null)
                        ratingProperty = pcol;
                }

                // if for any reason, the Rating property hasn't been created by the App developper, this
                // piece of code creates the PropertyInfo and ProgramProperty.
                if (ratingProperty == null)
                {
                    ProgramPropertyInfo pi = ProgramPropertyInfo.CreateProgramPropertyInfo(++propMax, "Rating", "Rating", "rating for a movie");
                    ratingProperty = ProgramProperty.CreateProgramProperty(pid, pi.pvid);
                    ratingProperty.PropertyInfo = pi;
                    ratingProperty.Program = program;
                    ratingProperty.Value = rating.ToString();                    

                    this.CurrentDataSource.AddToProgramPropertyInfoCollection(pi);
                    this.CurrentDataSource.AddToPropramProperties(ratingProperty);
                }

                if (program.Properties.Count != 0)
                {
                    var pcol = program.Properties.FirstOrDefault((v) => { 
                        if (v.PropertyInfo == null)
                            v.PropertyInfoReference.Load(); 
                        return ((v.PropertyInfo.Name == "NumberOfRating") && (v.programid == pid)); 
                    });

                    if (pcol != null)
                        ratingNumberProperty = pcol;
                }

                // if for any reason, the NumberOfRating property hasn't been created by the App developper, this
                // piece of code creates the PropertyInfo and ProgramProperty.
                if (ratingNumberProperty == null)
                {
                    ProgramPropertyInfo pi = ProgramPropertyInfo.CreateProgramPropertyInfo(++propMax, "NumberOfRating", "NumberOfRating", "number of people who rated a movie");
                    ratingNumberProperty = ProgramProperty.CreateProgramProperty(pid, pi.pvid);
                    ratingNumberProperty.PropertyInfo = pi;
                    ratingNumberProperty.Program = program;
                    ratingNumberProperty.Value = 1.ToString();                    

                    this.CurrentDataSource.AddToProgramPropertyInfoCollection(pi);
                    this.CurrentDataSource.AddToPropramProperties(ratingNumberProperty);
                }

                // Once the two ProgramProperty have been created/retrieved, we can calculate the average
                Double overallRating = Double.Parse(ratingProperty.Value);
                int overallNumber = int.Parse(ratingNumberProperty.Value);

                var userRating = (from ra in this.CurrentDataSource.Ratings
                             where ra.programid == pid && ra.UserIdentifier == userId
                             select ra).FirstOrDefault();

                if (userRating != null)
                {
                    Double oldRating = userRating.Rate;
                    userRating.Rate = rating;

                    newRating = ((((overallRating * overallNumber) - oldRating) + rating) / overallNumber);
                    newNumber = overallNumber;
                }
                else
                {
                    newRating = (((overallRating * overallNumber) + rating) / (overallNumber + 1));
                    newNumber = ++overallNumber;

                    /// Update the Rating Table to keep a trace on who voted and what was the user's rating for that 
                    /// given movie.
                    Rating r = Rating.CreateRating(rating, userId, pid);
                    r.Program = program;
                    this.CurrentDataSource.AddToRatings(r);
                }

                // final result - update the Property back with the new values (average, number of votes)
                ratingNumberProperty.Value = newNumber.ToString();
                ratingProperty.Value = newRating.ToString(); 
                result = newRating;
            }

            this.CurrentDataSource.SaveChanges();

            return new Double[] { result }.AsQueryable<Double>();
        }

        [WebGet]
        public void CreateCategory()
        {
            Category c = Category.CreateCategory(1, "Genre");
            c.Name = c.Value;
            this.CurrentDataSource.AddToCategories(c);

            Category c1 = Category.CreateCategory(2, "Comedy");
            c1.ParentCategory = c;
            c1.Name = c1.Value;
            c.ChildCategories.Add(c1);
            this.CurrentDataSource.AddToCategories(c1);

            Category c2 = Category.CreateCategory(3, "GameShow");
            c2.ParentCategory = c;
            c2.Name = c2.Value;
            c.ChildCategories.Add(c2);
            this.CurrentDataSource.AddToCategories(c2);

            Category c3 = Category.CreateCategory(4, "Drama");
            c3.ParentCategory = c;
            c3.Name = c3.Value;
            c.ChildCategories.Add(c3);
            this.CurrentDataSource.AddToCategories(c3);

            Category c4 = Category.CreateCategory(5, "News");
            c4.ParentCategory = c;
            c4.Name = c4.Value;
            c.ChildCategories.Add(c4);
            this.CurrentDataSource.AddToCategories(c4);

            Category c5 = Category.CreateCategory(6, "Sport");
            c5.ParentCategory = c;
            c5.Name = c5.Value;
            c.ChildCategories.Add(c5);
            this.CurrentDataSource.AddToCategories(c5);

            Category c6 = Category.CreateCategory(7, "Soap");
            c6.ParentCategory = c;
            c6.Name = c6.Value;
            c.ChildCategories.Add(c6);
            this.CurrentDataSource.AddToCategories(c6);

            Category c7 = Category.CreateCategory(8, "Kids");
            c7.ParentCategory = c;
            c7.Name = c7.Value;
            c.ChildCategories.Add(c7);
            this.CurrentDataSource.AddToCategories(c7);

            Category c8 = Category.CreateCategory(9, "Music");
            c8.ParentCategory = c;
            c8.Name = c8.Value;
            c.ChildCategories.Add(c8);
            this.CurrentDataSource.AddToCategories(c8);

            Category c9 = Category.CreateCategory(10, "Entertainment");
            c9.ParentCategory = c;
            c9.Name = c9.Value;
            c.ChildCategories.Add(c9);
            this.CurrentDataSource.AddToCategories(c9);

            this.CurrentDataSource.SaveChanges();
        }
    }
}
